
#include "cc_malloc.h"
#include "cc_pub.h"
/********* interior	define ***********/
#define LLOG
#define LLOG_ERR
#define LLOG_MARK
#define LLOG_ASSERT
#include "llog.h"

#define CFG_ALIGN_8_BYTE

#if 1 // 64Bit 系统
#define TYP_PTR_VAL	unsigned long long
#else 
#define TYP_PTR_VAL	uint32_t
#endif


#ifdef	CFG_STATIC_BUF_ALLOCATE
#define L_MALLOC 	SMalloc
#define L_FREE(A) 	LLOG_ERR()
#else
#define L_MALLOC 	malloc
#define L_FREE(A)	free(A)
#endif

// N-设计灵感来源与 UDS协议的PDU 
#define TBM_SF		0x01
#define TBM_FF		0x02
#define TBM_CF		0x03
#define TBM_NONE	0x00	// EMPTY

/********* interior  struct **********/
struct CC_Block_Pool{
	
	uint16_t BlockSz;
	uint16_t BlockNum;
	uint8_t* pBuf; 			// ObjSz*PoolObjNum	
	
	uint16_t Used;
	uint16_t BitMapSz;		// PoolObjNum >> 3+PoolObjNum		
	uint8_t* pBitMap;		// 
};

/********** global val ***************/
#ifdef CFG_DYNAMIC_ALLOCATE 	

static uint8_t g_TwoBitMap_Shift[]={
	6,4,2,0,
};
static uint8_t g_TwoBitMap_Mask[]={
	0xC0,0x30,0x0C,0x03,
};

#endif
/******* local function **************/

/******* TODO ************************/

// 
#ifdef CFG_DYNAMIC_ALLOCATE

void BlkPool_ShowBMap(uint8_t* pStr,tBlkPool* pObj){
	if(pStr!=NULL){
		LLOG("%s used[%d]\n",pStr,pObj->Used);
	}	
	Log_ShowArray("BlkPool BMap",pObj->BitMapSz,pObj->pBitMap);
}

void BlkPool_Show(uint8_t* pStr,tBlkPool* pObj){
	
	if(pStr!=NULL){
		LLOG("%s\n",pStr);
	}
	LLOG(" ObjPoolAddr  [%x]\n" ,(TYP_PTR_VAL)pObj);
	LLOG(" BlockSz		[%d]\n"	,pObj->BlockSz		);			// 
	LLOG(" BlockNum		[%d]\n"	,pObj->BlockNum);	
	LLOG(" pBuf			[%x]\n"	,pObj->pBuf		);
	LLOG(" Used			[%d]\n"	,pObj->Used		);
	LLOG(" BitMapSz		[%d]\n"	,pObj->BitMapSz	);
	LLOG(" pBitMap		[%x]\n"	,pObj->pBitMap	);	
}
//
static uint16_t Calc_AlignBitMapSz(uint16_t BitMapSz){
	
	uint16_t AlignBitMapSz;
	
	#ifdef CFG_ALIGN_8_BYTE  // TODO:byte对齐
	if(BitMapSz&0x07){ // 8byte 对齐
		AlignBitMapSz = (BitMapSz&(~0x0007))+8;
	}
	else{
		AlignBitMapSz = BitMapSz;
	};	
	#endif
	
	#ifdef CFG_ALIGN_4_BYTE 
	if(BitMapSz&0x03){
		AlignBitMapSz=(BitMapSz&(~0x0003))+4;
	}
	else{
		AlignBitMapSz=BitMapSz;
	};
	#endif	
	
	return AlignBitMapSz;
}

tBlkPool* BlkPool_Create(uint16_t BlockSz,uint16_t BlockNum){

	tBlkPool* ptmp=NULL;
	uint8_t* pBuf=NULL;
	
	uint16_t BitMapSz;
	uint16_t AlignBitMapSz;
	uint16_t BlkBufSz;
	uint16_t ObjStructSz;
	
	BitMapSz=BlockNum>>2;
	BitMapSz+=(BlockNum&0x03)?1:0;
	
	AlignBitMapSz = Calc_AlignBitMapSz(BitMapSz);

	ObjStructSz=sizeof(tBlkPool);
	BlkBufSz=BlockSz*BlockNum;
	
	pBuf = L_MALLOC(ObjStructSz+AlignBitMapSz+BlkBufSz);
	ptmp = (tBlkPool*)pBuf;
	if(ptmp == NULL){
		return ptmp;
	}
	MEMSET(pBuf,0,ObjStructSz+AlignBitMapSz+BlkBufSz);
	
	ptmp->BlockSz	= BlockSz;
	ptmp->BlockNum	= BlockNum;
	ptmp->pBuf		= &pBuf[ObjStructSz+AlignBitMapSz];
	ptmp->BitMapSz	= BitMapSz;
	ptmp->pBitMap	= &pBuf[ObjStructSz];
	
	// TODO: 设置最后多余的几bit 
	// N-注意强制全部清除 或者会造成bug 内存溢出
	ptmp->pBitMap[BitMapSz-1]=0x55>>((BlockNum&0x03)*2);
	
	return ptmp;
}

uint8_t* BlkPool_DynAlloc(tBlkPool* pObj,uint16_t ByteNum){
	uint8_t* ptmp=NULL;
	int Index;
	uint16_t NeedBlkNum;
	uint32_t ActiveNum;
	int i,j;
	uint8_t* pBuf;
	uint16_t BufSz;
	
	pBuf	= pObj->pBitMap;
	BufSz	= pObj->BitMapSz;
	ActiveNum=BufSz<<2;
	
	NeedBlkNum = 	ByteNum/pObj->BlockSz;
	NeedBlkNum +=	(ByteNum%pObj->BlockSz)?1:0;
	
	L_PARA_CHECK(NeedBlkNum > 0,ptmp);
	L_PARA_CHECK(NeedBlkNum < ActiveNum,ptmp);
	
//	index = TBMap_FindEmptySpace(pObj->BitMapSz,pObj->pBitMap,NeedBlkNum);
	do{
		uint16_t Cnt;
		uint8_t tmp;
		Index=-1;
		Cnt=0;
		for(i=0;i<BufSz;i++){
			tmp=pBuf[i];
			for(j=0;j<4;j++){
				if(tmp&g_TwoBitMap_Mask[j]){	
					Cnt=0;
				}
				else{
					Cnt++;	
					if(Cnt == NeedBlkNum){
						// LLOG("#I i[%d] j[%d] Cnt[%d]\n",i,j,Cnt);
						Index=(i*4+j+1)-Cnt; 
						goto FIND_OUT;
					}			
				}
			}
		}
		FIND_OUT:
		if(Index < 0){
			return NULL;
		}
	}while(0);
//	L_PARA_CHECK(Index >= 0);
//	L_PARA_CHECK(Index < ActiveNum,ptmp);
//	L_PARA_CHECK(Index+NeedBlkNum <= ActiveNum,ptmp);
	
	// TBMap_SetMark(pObj->BitMapSz,pObj->pBitMap,index,NeedBlkNum);
	do{
		uint16_t ByteIdx;
		uint8_t Ofs;	

		ByteIdx	= Index>>2; // 1byte==4Item;
		Ofs	= Index&0x03;	
		// LLOG("#I Idx[%d] Ofs[%d]\n",ByteIdx,Ofs);
		if(NeedBlkNum == 1){
			pBuf[ByteIdx]|=(TBM_SF<<g_TwoBitMap_Shift[Ofs]);		
		}
		else{
			i=0;
			j=0;
			pBuf[ByteIdx+j]|=(TBM_FF<<g_TwoBitMap_Shift[Ofs++]);	
			for(i=1;i<NeedBlkNum;i++){
				if(Ofs>=4){
					j++;
					Ofs=0;
				}			
				pBuf[ByteIdx+j]|=(TBM_CF<<g_TwoBitMap_Shift[Ofs++]);
			}
		}	
	}while(0);
	pObj->Used += (NeedBlkNum);
	ptmp = &pObj->pBuf[pObj->BlockSz*Index];
	
	
	#if 0 //
	L_PARA_CHECK( !(((TYP_PTR_VAL)ptmp)&0x03) ) // check 非 8byte 对齐
	// LLOG(" Addr[%x]\n",(TYP_PTR_VAL)ptmp);	// 检查是否地址对齐	
	#endif
	
	return ptmp;
}

int BlkPool_Release(tBlkPool* pObj,void* ptmp){
	
	int ret = -1;
	int	Index=-1;
	TYP_PTR_VAL tmp;
	TYP_PTR_VAL diff;
	uint32_t BlockSz;
	
	// 1- 将 指针转换为 对于的 Block_Index	
	tmp = (TYP_PTR_VAL)&pObj->pBuf[0];
	BlockSz = pObj->BlockSz; 
	diff = (BlockSz*pObj->BlockNum);
	
	L_PARA_CHECK( ((TYP_PTR_VAL)ptmp) >= tmp		,ret);
	L_PARA_CHECK( ((TYP_PTR_VAL)ptmp) <= (tmp+diff),ret);

	diff	=	( ((TYP_PTR_VAL)ptmp) - tmp);
	Index	=	diff/BlockSz;	// 检查没有余数 ：指针对齐
	L_PARA_CHECK(diff ==  Index*BlockSz,ret);
	// =====
	do{
		int i,j;
		// Step1 定位
		uint16_t ByteIdx;
		uint8_t Ofs;
		uint16_t ActiveNum;
		uint8_t tmp;
		
		uint8_t* pBuf;
		uint16_t BufSz;
		
		pBuf	= pObj->pBitMap;
		BufSz	= pObj->BitMapSz;	
			
		ActiveNum = BufSz << 2;
		
		if(Index > ActiveNum){
			LLOG("E Index=%d , ActiveNum=%d\n",Index,ActiveNum);
			LLOG_ERR();
			return ret;
		}
		// L_PARA_CHECK(Index <= ActiveNum,ret);

		ByteIdx =Index>>2;
		Ofs =Index&0x03;
		
		// 
		i=0;
		tmp=(pBuf[ByteIdx]>>g_TwoBitMap_Shift[Ofs])&0x03;
		
		switch(tmp){
			case TBM_SF:{
				pBuf[ByteIdx]&=(~g_TwoBitMap_Mask[Ofs]); i++;
				
				pObj->Used -= i;
				MEMSET(ptmp,0,BlockSz*i); // 清除DataBuf	
				// ret = RET_OK;
			}break;
			case TBM_FF:{
				uint16_t Cnt;
				j=0;
				ActiveNum-=Index; // 剩余数量
				// LLOG("Res%d\n",ActiveNum);
				pBuf[ByteIdx+j]&=(~g_TwoBitMap_Mask[Ofs++]);i++; // Clean FF
			
				for(Cnt = 1;Cnt < ActiveNum;Cnt++){// N-Clean CF 
					if(Ofs>=4){
						j++;
						Ofs=0;
					}			
					tmp=(pBuf[ByteIdx+j]>>g_TwoBitMap_Shift[Ofs])&0x03;
					if(tmp != TBM_CF){
						break;
					}
					pBuf[ByteIdx+j]&=(~g_TwoBitMap_Mask[Ofs++]);i++;
				}			
				//
				pObj->Used -= i;
				MEMSET(ptmp,0,BlockSz*i);// 清除DataBuf		
				// ret = RET_OK;
			}break;
			case TBM_CF:{	// 非头块
				LLOG_ERR();
			}break;
			case TBM_NONE:{ // 已经释放
				
			}break;
			default:{}
		}
		ret = i;
	}while(0);
		
	return ret;
}

// for UT
int BlkPool_CmpBMap(tBlkPool* pObj,uint8_t* pCmpBuf){
	int ret = RET_OK;
	int i;
	for(i=0;i<pObj->BitMapSz;i++){
		if(pObj->pBitMap[i] != pCmpBuf[i]){
			ret=RET_ERR;
			break;
		}
	}
	return ret;
}

#endif


#ifdef CFG_SYS_MALLOC // App层 

static tBlkPool* g_pMemHeap = NULL;
void MemHeap_Init(uint16_t BNum){ // 选8的倍数对齐
	uint32_t BlockNum;
	
	// BlockNum = 	BNum>>3;
	// BlockNum += (BNum&0x07)?1:0;

	BlockNum = 	BNum/CFG_MEM_BLOCK_SZ;
	BlockNum += (BNum%CFG_MEM_BLOCK_SZ)?1:0;
	
	LLOG("#I CFG_MEM_BLOCK_SZ %d,BlockNum %d \n",CFG_MEM_BLOCK_SZ,BlockNum);
	g_pMemHeap = BlkPool_Create(CFG_MEM_BLOCK_SZ,BlockNum);
}

void* MemHeap_Alloc(uint16_t ByteNum,uint16_t Line){
	uint8_t* ptmp=NULL;
	ptmp=BlkPool_DynAlloc(g_pMemHeap,ByteNum);
	if(ptmp == NULL)
		LLOG("#E MemAlloc L[%d]\n",Line);
	return (void*)ptmp;
}

int MemHeap_Free(void* ptmp,uint16_t Line){
	int ret;
	ret = BlkPool_Release(g_pMemHeap,ptmp);
	if(ret == -1){
		LLOG("#E MemFree L[%d]\n",Line);
	}
	// LLOG("#I MemFree ret=[%d] L[%d]\n",ret,Line);
	return ret;
}

void MemHeap_ShowUsed(void){
	LLOG("#I MemHeap Used[%d] Total[%d]\n",g_pMemHeap->Used,g_pMemHeap->BlockNum);
}

void MemHeap_ShowBiMap(void){
	BlkPool_ShowBMap("#I SysHeap bitmap",g_pMemHeap);
}
#endif



